package ca.etrange.beerscreen.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Observable;
import java.util.TooManyListenersException;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;

/* uses filemonitor as example */
public class ArduinoBeerMonitor extends Observable {
	private final static String DEFAULT_PORT = "COM5";
	private final static int PORT_RATE = 9600;
	private final static int PORT_TIMEOUT = 2000;
	private SerialPort serialPort;
	private CommPortIdentifier portId;
	private InputStream readStream;
	private StringBuilder readBuffer;
	
	public ArduinoBeerMonitor(String comPort, int numKegs, boolean hasTemp, 
			boolean hasProximitySensor) throws PortNotFoundException, 
			PortInUseException {
		
		// Setup read buffer
		readBuffer = new StringBuilder();
		
		// Find the port identifier
		Enumeration<CommPortIdentifier> ports = 
			CommPortIdentifier.getPortIdentifiers();
		
		boolean portFound = false;
		while(ports.hasMoreElements()){
			portId = ports.nextElement();
			if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
				if (portId.getName().equals(DEFAULT_PORT )) {
					portFound = true;
					break;
				}
			}
		}
		
		if(!portFound){
			// problem, do something later.
			System.out.println("Port not found!");
			throw new PortNotFoundException();
		}
		
		// init the port
		// will throw PortInUseException if in use
		serialPort = (SerialPort) portId.open("Arduino", PORT_TIMEOUT);
		
		try {
			serialPort.setSerialPortParams(PORT_RATE, SerialPort.DATABITS_8, 
					SerialPort.STOPBITS_1, 
					SerialPort.PARITY_NONE);

			readStream = serialPort.getInputStream();
		} catch (IOException e1) {
			e1.printStackTrace();
		} catch (UnsupportedCommOperationException e) {
			e.printStackTrace();
		}
		
		// Add receive listener
		try {
			serialPort.addEventListener(new SerialPortEventListener() {
				public void serialEvent(SerialPortEvent event) {
					switch(event.getEventType()){
						case SerialPortEvent.DATA_AVAILABLE:
							readSerialData();
							break;
						default:
							break;
					}
				}
			});
		} catch (TooManyListenersException e) {
			// maybe we should throw this one 
			e.printStackTrace();
		}
		
		// Insure that the listener will be called
		serialPort.notifyOnDataAvailable(true);
	}
	
	/**
	 * Read the serial data and notify listeners
	 */
	private void readSerialData(){
		try {
			while(readStream.available() > 0){
				char current = (char)readStream.read();
				if(current == '.'){
					final String values[] = readBuffer.toString().split(";");
					readBuffer = new StringBuilder(); //clear buffer
					this.setChanged();
					this.notifyObservers(values);
				} else {
					readBuffer.append(current);
				}

			}
		} catch (IOException ioe){
		}
	}
}
